/* This file contine the process captured buffer,
 * Currently,	1. output to a lot of jpeg pictures
 *		2. Output to a raw yuv422 format raw movie, [buggy]
 *
 * Author: kzjeef@gmail.com
 * Date  : 2008.11.23
 *
 */

#include "capture.h"

static void
put_jpeg_image (const char *image , size_t length)
{
        assert (image );
        assert (length > 0);
        int width	= _width;
        int height	= _height;
        int quality	= _quality;
        char fnamebuf[100];

        static int jpeg_count  = 0;
        CLEAR(fnamebuf);

#ifdef HAVE_LIBJPEG
        int y, x, line_width;
        JSAMPROW row_ptr[1];
        struct jpeg_compress_struct cjpeg;
        struct jpeg_error_mgr jerr;
        char *line;
        FILE *longxin_fd ;

#ifdef RGB4
        const int gap = 4;
#else
        const int gap = 3;
#endif

        sprintf(fnamebuf, "/tmp/capture_%d_file.jpg", jpeg_count);

        jpeg_count++;

        if ( jpeg_count < 15 )	/* drop first 15 pics , since it was black */
                return ;
        longxin_fd = fopen (fnamebuf,"w");

        if (longxin_fd < 0 ) printf ("open jpeg name %s error:%s ",fnamebuf,strerror(errno) );

        int size = width * gap* 8*10 ;
        line = malloc (size );
        if (verbose) fprintf(stderr, "line :0x%x with length %dKB\n", (unsigned int)line,size>>10);
        if (!line)
                return;
        cjpeg.err = jpeg_std_error(&jerr);
        jpeg_create_compress (&cjpeg);
        cjpeg.image_width = width;
        cjpeg.image_height= height;
        cjpeg.input_components = 3;
        cjpeg.in_color_space = JCS_RGB;
        jpeg_set_defaults (&cjpeg);
        jpeg_set_quality (&cjpeg, quality, TRUE);
        cjpeg.dct_method = JDCT_FASTEST;
//	jpeg_stdio_dest (&cjpeg, stdout);
        jpeg_stdio_dest (&cjpeg,longxin_fd);

        jpeg_start_compress (&cjpeg, TRUE);

        row_ptr[0] = (JSAMPROW)line;
        line_width = width * gap;
        line_width = width * gap;

        if (verbose)
                printf ("width :%d height :%d line_width :%d\n",
                        width,
                        height,
                        line_width);

        for ( y = 0; y < height; y++) {
                for (x = 0; x < line_width; x+=gap) {
                        line[x]   = image[x+2];
                        line[x+1] = image[x+1];
                        line[x+2] = image[x];
                }
                jpeg_write_scanlines (&cjpeg, row_ptr, 1);
                image += line_width;
        }
        jpeg_finish_compress (&cjpeg);
        jpeg_destroy_compress (&cjpeg);
        free (line);
        fclose (longxin_fd);
#endif
}

static inline void yuv2bitmap(unsigned char *bitmap, int y, int u, int v)
{
        int r= 0, g= 0, b= 0;

        // u and v are +-0.5
        u -= 128;
        v -= 128;
        r = y + 1.370705 * v;
        g = y - 0.698001 * v - 0.337633 * u;
        b = y + 1.732446 * u;

        // Clamp to 0..1
        if (r < 0) r = 0;
        if (g < 0) g = 0;
        if (b < 0) b = 0;
        if (r > 255) r = 255;
        if (g > 255) g = 255;
        if (b > 255) b = 255;

        /* be aware that rgb format r byte g byte and b byte was in
         * order like below, please don't try other order.*/
        bitmap[0] = r;
        bitmap[1] = g;
        bitmap[2] = b;
#ifdef RGB4
        /* RGB4 was not ued . */
        bitmap[3] = 0;
#endif

}


inline void conv_422_rgb_sub(const unsigned char *yuv, unsigned char *rgb1,unsigned char *rgb2)
{
        int y1, y2, u, v;

        /* be aware that u ,v may exchange their position , because u
         * and v 's position was not defined very clear , if your
         * picture seems color not normal, you may try to exchang u
         * and v 's order  */

        y1 = yuv[0];
        u = yuv[3];
        y2 = yuv[2];
        v = yuv[1];
        yuv2bitmap(rgb1, y1, u, v);
        yuv2bitmap(rgb2, y2, u, v);
}

static void
uyuv422_rgb (const void *puyuv, void *prgb, size_t lenyuv, size_t lenrgb)
{
        /* uyuv have 2 bytes, and rgb request 4 bytes */
#ifdef RGB4
        int gap = 4;
#else
        int gap = 3;
#endif
        assert (((lenyuv >> 1) * gap) == lenrgb);
        int  j;
        void *rgb_offset = prgb;
        const void *yuv_offset = puyuv;
        for (j = 0; j < lenyuv; j += 4 ) {
                conv_422_rgb_sub(yuv_offset,
                                 rgb_offset,
                                 rgb_offset + gap);
                yuv_offset += 4 ;
                rgb_offset += gap * 2;
        }
}

void
process_image  (const void * p, size_t length)
{
        static int count  = 0;

        assert(p);
        assert(length > 0);
        if (verbose)
                printf("p: 0x%X, length: %dKB \n", (unsigned int)p, length>>10);

        fputc ('.', stdout);
        fflush (stdout);


        if (!output_jpeg) {
                if (write (test_file_fd, p, length) != length)
                        perror ("write error");
        } else {

#ifdef RGB4
        char buf[length * 2];
#else
        char buf[(length>>1) * 3];
#endif
                memset (buf, 0, sizeof(buf));
                uyuv422_rgb (p, buf, length, sizeof(buf));
                put_jpeg_image (buf , sizeof(buf));
        }

}
